from picshell.parser.JalV2AsmParser import JalV2AsmParser
from picshell.parser.AnnotationParser import AnnotationParser
from picshell.engine.core.PicThreadEngine import PicThreadEngine
from picshell.engine.core.PicEngine import PicEngine
from picshell.util.AssertUtil import AssertUtil

def get_pictype( asmFileName ):
	ret = "unknown"

	fin = open(asmFileName,"r")   
	for line in fin: 
	   poss = line.find("list p=" )

	   pose = line.find(",",poss )
	      
	   if ( poss >= 0 ) and ( pose > 0 ):
	   	ret = line[poss+len("list p="):pose]
	fin.close()
	ret = (ret.lstrip()).rstrip()
	return ret
   			

def picshell_unittest(jalFileName,asmFileName,hexFileName):
	picTypeName = get_pictype( asmFileName )
	asmParser = JalV2AsmParser()
	wholeCode = asmParser.parseAsmFile(asmFileName, [])
	varTypeDict = JalV2AsmParser.buildVarTypeDict(wholeCode)
	
	parseRes = AnnotationParser.parse(file(jalFileName).read())
	noDebugList = parseRes["noDebug"]
	debugList = parseRes["debug"]
	langParser = JalV2AsmParser()
	code = langParser.parseAsmFile(asmFileName, noDebugList,debugList)
	
	def unittest_callback(address,oracle):
		line = langParser.adrToLine[address]
		if line != None:
			txt = code[line].line
			assertTag = AssertUtil.GetAssertTag( txt )                
			if assertTag != None:                	 
				res = AssertUtil.parse(txt,assertTag)
				var = res["var"].lower()
				label = res["label"]
				ref = res["ref"]
				if (langParser.varAdrMapping.has_key("v_"+str(var))):
					varAddr = langParser.varAdrMapping["v_"+str(var)]
					varType = type = varTypeDict.get(var,'bit')
					val = emu.varValue(varAddr,varType)

					[assertRes, cmpStr ] = AssertUtil.Assert( assertTag, val, ref )               
					res= varType+ " " + var + " (@"+str(varAddr)+") = 0x%X " % val + cmpStr + " expected : 0x%X" % ref
	
					print label,
					if assertRes :
						oracle['success'] += 1
						print ": OK"
					else :
						oracle['failure'] += 1
						print ": FAIL, " + res
				else:
					oracle['notrun'] += 1
					print "Can't run test '%s' because var '%s' can't be found" % (label,var)
	
	emu = PicEngine.newInstance(picTypeName,hexFileName)
	
	#		  success failure notrun
	oracle = {'success' : 0, 'failure' : 0, 'notrun' : 0}
	def run(to,emu,unittest_callback):
		current_address = emu.runNext()
		while current_address != to:
			#unit testing ?
			if unittest_callback != None:
				unittest_callback(current_address,oracle)
			current_address = emu.runNext()
		# last call on finishing address
		unittest_callback(current_address,oracle)

	if picTypeName.startswith( "18f" ):
		run(emu.lastAddress-2,emu,unittest_callback)
	else:
		run(emu.lastAddress,emu,unittest_callback)
	
	return oracle
	
	
if __name__ == '__main__':
	import getopt
	import os
	import sys
	
	usage = '''picshell_unittest.
Usage:
    python picshell_unittest.py [options] file.jal

Arguments:
    file.jal                name of jal file to analyze.
                            assumption is that file is compiled, and that the hex and assembly file are
                            generated and located in the same directory
Options:
    -h, --help              this help message.
    -o, --output_file       write results also to the output file
'''

	output_file = ""
		
	try:
		opts, args = getopt.getopt(sys.argv[1:], "ho:",
		                         ["help", "output_file"])

		for o, a in opts:
			if o in ("-h", "--help"):
				print usage
				sys.exit(0)
			elif o in ("-o", "--output_file"):
				try:
					output_file = a
				except:
					raise getopt.GetoptError, 'Bad output file name format '
			
		if not args:
			raise getopt.GetoptError, 'Jal file is not specified'
			
		if len(args) > 2:
			raise getopt.GetoptError, 'Too many arguments'

	except getopt.GetoptError, msg:
		print msg
		print usage
		sys.exit(2)

	command = args[0]

	filename = args[len(args) - 1]
	print "FILENAME " + filename

	jal = filename
	asm = filename.replace(".jal",".asm")
	hex = filename.replace(".jal",".hex")
	oracle = picshell_unittest( jal, asm, hex )
	print "Test results: %s" % oracle

	if len( output_file ) > 0:
		fout = file(output_file,"wb")
		fout.write(str( oracle ) )
		fout.close()
	   

	sys.exit( 0 )
	